#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QFile>
#include <QLocale>
#include <QAction>
#include <QDateTime>
#include <QScrollBar>
#include <QFileDialog>
#include <QMessageBox>
#include <QActionGroup>
#include <QHostAddress>
#include <QNetworkInterface>

enum {
    NET_PROTO_UDP,
    NET_PROTO_TCP_CLIENT,
    NET_PROTO_TCP_SERVER,
    NET_PROTO_PING
};

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    rx(0), tx(0), sequence(0),
    udpSock(NULL), tcpSock(NULL), tcpServer(NULL), rawSock(NULL)
{
    ui->setupUi(this);

    QMenu *titleMenu = new QMenu(this);
    languageMenu = titleMenu->addMenu(tr("Language"));

    QActionGroup *group = new QActionGroup(this);
    group->setExclusive(true);

    QAction *langEn = languageMenu->addAction("English");
    QAction *langZh = languageMenu->addAction("中文");
    languageMenu->addSeparator();
    langAuto = languageMenu->addAction(tr("自动"));

    langEn->setActionGroup(group);
    langZh->setActionGroup(group);
    langAuto->setActionGroup(group);

    langEn->setCheckable(true);
    langZh->setCheckable(true);
    langAuto->setCheckable(true);
    langAuto->setChecked(true);

    connect(languageMenu, SIGNAL(triggered(QAction *)), this, SLOT(setLanguage(QAction *)));

    about = titleMenu->addAction(tr("关于"));
    aboutQt = titleMenu->addAction(tr("关于Qt"));
    connect(about, SIGNAL(triggered(bool)), this, SLOT(showAbout()));
    connect(aboutQt, SIGNAL(triggered(bool)), this, SLOT(showAboutQt()));
    ui->pushButtonMenu->setMenu(titleMenu);

    statusTx = new QLabel;
    statusTx->setMinimumSize(100, 20);
    statusTx->setFrameShape(QFrame::WinPanel);
    statusTx->setFrameShadow(QFrame::Sunken);

    statusRx = new QLabel;
    statusRx->setMinimumSize(100, 20);
    statusRx->setFrameShape(QFrame::WinPanel);
    statusRx->setFrameShadow(QFrame::Sunken);

    statusRstBtn = new QPushButton;
    connect(statusRstBtn, SIGNAL(clicked()), this, SLOT(on_statusRstBtnClicked()));

    ui->statusBar->addPermanentWidget(statusTx);
    ui->statusBar->addPermanentWidget(statusRx);
    ui->statusBar->addPermanentWidget(statusRstBtn);

    InitLocalIP();

    connect(&timer, SIGNAL(timeout()), this, SLOT(timeUpDate()));

    recvMenu = new QMenu(this);
    clear = recvMenu->addAction(style()->standardIcon(QStyle::SP_LineEditClearButton), tr("清除"));
    save = recvMenu->addAction(style()->standardIcon(QStyle::SP_DialogSaveButton), tr("保存"));
    connect(clear, SIGNAL(triggered(bool)), this, SLOT(clearRecv()));
    connect(save, SIGNAL(triggered(bool)), this, SLOT(saveRecv()));

    ui->splitterUdp->setStretchFactor(0, 10);
    ui->splitterUdp->setStretchFactor(1, 1);

    ui->lineEditSendCycle->setValidator(new QIntValidator(ui->lineEditSendCycle));
    ui->lineEditLocalPort->setValidator(new QIntValidator(0, 65536, ui->lineEditSendCycle));
    ui->lineEditSrvPort->setValidator(new QIntValidator(0, 65536, ui->lineEditSendCycle));

    QRegExp ipexp("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$");
    ui->lineEditSrvAddr->setValidator(new QRegExpValidator(ipexp, ui->lineEditSrvAddr));

    ui->comboBoxProto->addItem("UDP", NET_PROTO_UDP);
    ui->comboBoxProto->addItem(tr("TCP客户端"), NET_PROTO_TCP_CLIENT);
    ui->comboBoxProto->addItem(tr("TCP服务器"), NET_PROTO_TCP_SERVER);
    ui->comboBoxProto->addItem("PING", NET_PROTO_PING);

    connect(ui->comboBoxProto, SIGNAL(currentIndexChanged(int)), SLOT(on_comboBoxProtoChanged()));

    setLanguage(NULL);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_statusRstBtnClicked()
{
    rx = 0;
    tx = 0;

    statusRx->setText(tr("接收") + "：0");
    statusTx->setText(tr("发送") + "：0");
}

void MainWindow::InitLocalIP()
{
    QList<QHostAddress> AddressList = QNetworkInterface::allAddresses();

    foreach(QHostAddress address, AddressList) {
        if(address.protocol() != QAbstractSocket::IPv4Protocol)
            continue;
        ui->comboBoxLocalAddr->addItem(address.toString());
    }
}

bool MainWindow::isOpened()
{
    QAbstractSocket *s = NULL;
    int proto = ui->comboBoxProto->currentData().toInt();

    switch (proto) {
    case NET_PROTO_UDP:
        s = udpSock;
        break;
    case NET_PROTO_TCP_CLIENT:
        s = tcpSock;
        break;
    case NET_PROTO_TCP_SERVER:
        return (tcpServer && tcpServer->isListening());
    case NET_PROTO_PING:
        s = rawSock;
        break;
    default:
        return false;
    }

    return (s && s->state() != QAbstractSocket::UnconnectedState);
}

void MainWindow::closeSock()
{
    int proto = ui->comboBoxProto->currentData().toInt();

    switch (proto) {
    case NET_PROTO_UDP:
        delete udpSock;
        qDebug() << "Close udp socket";
        break;
    case NET_PROTO_TCP_CLIENT:
        delete tcpSock;
        qDebug() << "Close tcp socket";
        break;
    case NET_PROTO_TCP_SERVER: {
        QMapIterator <QTcpSocket *, int> i(tcpClients);
        while (i.hasNext()) {
            i.next();
            QTcpSocket *cli = i.key();
            cli->close();
        }
        delete tcpServer;
        qDebug() << "Close tcp server socket";
        break;
    }
    case NET_PROTO_PING:
        delete rawSock;
        qDebug() << "Close icmp socket";
        break;
    default:
        break;
    }
}

void MainWindow::initUi()
{
    int proto = ui->comboBoxProto->currentData().toInt();

    clear->setText(tr("清除"));
    save->setText(tr("保存"));

    about->setText(tr("关于"));
    aboutQt->setText(tr("关于Qt"));

    statusRstBtn->setText(tr("复位计数"));
    statusRx->setText(tr("接收") + QString("：%1").arg(rx));
    statusTx->setText(tr("发送") + QString("：%1").arg(tx));

    langAuto->setText(tr("自动"));
    languageMenu->setTitle(tr("Language"));

    ui->comboBoxProto->setItemText(NET_PROTO_TCP_CLIENT, tr("TCP客户端"));
    ui->comboBoxProto->setItemText(NET_PROTO_TCP_SERVER, tr("TCP服务器"));

    ui->comboBoxAddrList->clear();

    if (proto == NET_PROTO_UDP || proto == NET_PROTO_TCP_SERVER || proto == NET_PROTO_PING) {
        ui->labelLocalAddr->show();
        ui->comboBoxLocalAddr->show();

        ui->labelSrvAddr->hide();
        ui->lineEditSrvAddr->hide();
        ui->labelSrvPort->hide();
        ui->lineEditSrvPort->hide();

        ui->labelAddrList->show();
        ui->comboBoxAddrList->show();
        ui->pushButtonAddrList->show();
    }

    if (proto == NET_PROTO_TCP_SERVER) {
        ui->labelAddrList->setText(tr("客户端："));
        ui->pushButtonAddrList->setText(tr("断开"));
        ui->comboBoxAddrList->setEditable(false);
    } else {
        ui->labelAddrList->setText(tr("对端主机："));
        ui->pushButtonAddrList->setText(tr("清除"));
        ui->comboBoxAddrList->setEditable(true);
    }

    if (proto == NET_PROTO_UDP || proto == NET_PROTO_TCP_SERVER) {
        ui->labelLocalPort->show();
        ui->lineEditLocalPort->show();
    }

    if (proto == NET_PROTO_TCP_CLIENT) {
        ui->labelLocalAddr->hide();
        ui->comboBoxLocalAddr->hide();
        ui->labelLocalPort->hide();
        ui->lineEditLocalPort->hide();

        ui->labelSrvAddr->show();
        ui->lineEditSrvAddr->show();
        ui->labelSrvPort->show();
        ui->lineEditSrvPort->show();

        ui->labelAddrList->hide();
        ui->comboBoxAddrList->hide();
        ui->pushButtonAddrList->hide();
    }

    if (proto == NET_PROTO_UDP) {
        QRegExp ipportexp("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?):([0-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$");
        ui->comboBoxAddrList->setValidator(new QRegExpValidator(ipportexp, ui->comboBoxAddrList));
        ui->comboBoxAddrList->addItem(ui->comboBoxLocalAddr->itemText(1) + QString(":8080"));
        ui->comboBoxAddrList->addItem("All");
    } else if (proto == NET_PROTO_PING) {
        QRegExp ipexp("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$");
        ui->comboBoxAddrList->setValidator(new QRegExpValidator(ipexp, ui->lineEditSrvAddr));
        ui->comboBoxAddrList->addItem(ui->comboBoxLocalAddr->itemText(1));
        ui->comboBoxAddrList->addItem("All");
    }

    if (proto == NET_PROTO_PING) {
        ui->checkBoxAutoLinefeed->hide();
        ui->checkBoxShowTime->hide();
        ui->checkBoxShowHex->hide();
        ui->checkBoxSendHex->hide();
        ui->plainTextEditSend->hide();
    } else {
        ui->checkBoxAutoLinefeed->show();
        ui->checkBoxShowTime->show();
        ui->checkBoxShowHex->show();
        ui->checkBoxSendHex->show();
        ui->plainTextEditSend->show();
    }

    if (isOpened()) {
        ui->comboBoxProto->setEnabled(false);
        ui->comboBoxLocalAddr->setEnabled(false);
        ui->lineEditLocalPort->setEnabled(false);
        ui->lineEditSrvAddr->setEnabled(false);
        ui->lineEditSrvPort->setEnabled(false);
        ui->comboBoxAddrList->setEnabled(true);
        ui->pushButtonAddrList->setEnabled(true);
        ui->pushButtonOpen->setText(tr("关闭"));

        switch (proto) {
        case NET_PROTO_TCP_CLIENT:
            ui->pushButtonSend->setEnabled(false);
            break;
        default:
            ui->pushButtonSend->setEnabled(true);
            break;
        }
    } else {
        timer.stop();
        ui->plainTextEditRecv->clear();
        ui->checkBoxToFile->setCheckState(Qt::Unchecked);

        ui->comboBoxProto->setEnabled(true);
        ui->comboBoxLocalAddr->setEnabled(true);
        ui->lineEditLocalPort->setEnabled(true);
        ui->lineEditSrvAddr->setEnabled(true);
        ui->lineEditSrvPort->setEnabled(true);
        ui->pushButtonSend->setEnabled(false);
        ui->pushButtonSend->setText(tr("发送"));
        ui->checkBoxSendHex->setEnabled(true);
        ui->checkBoxAutoSend->setEnabled(true);
        ui->lineEditSendCycle->setEnabled(true);
        ui->plainTextEditSend->setEnabled(true);
        ui->comboBoxAddrList->setEnabled(false);
        ui->pushButtonAddrList->setEnabled(false);

        switch (proto) {
        case NET_PROTO_UDP:
            ui->pushButtonOpen->setText(tr("绑定"));
            break;
        case NET_PROTO_TCP_CLIENT:
            ui->pushButtonOpen->setText(tr("连接"));
            break;
        case NET_PROTO_TCP_SERVER:
            ui->pushButtonOpen->setText(tr("监听"));
            break;
        case NET_PROTO_PING:
            ui->pushButtonOpen->setText(tr("打开"));
            break;
        default:
            break;
        }
    }
}

void MainWindow::on_pushButtonOpen_clicked()
{
    if (isOpened()) {
        closeSock();
        initUi();
        return;
    }

    QString ip, port;
    int proto = ui->comboBoxProto->currentData().toInt();

    switch (proto) {
    case NET_PROTO_UDP:
        ip = ui->comboBoxLocalAddr->currentText();
        port = ui->lineEditLocalPort->text();

        udpSock = new QUdpSocket(this);
        udpSock->bind(QHostAddress(ip), port.toUShort());
        connect(udpSock, SIGNAL(readyRead()), this, SLOT(onDataReceived()));

        qDebug() << "Bind UDP Socket at" << ip << port;
        break;

    case NET_PROTO_TCP_CLIENT:
        ip = ui->lineEditSrvAddr->text();
        port = ui->lineEditSrvPort->text();

        if (ip.isEmpty()) {
            QMessageBox::warning(NULL, tr("警告"), tr("请输入服务器IP地址"));
            return;
        }

        if (port.isEmpty()) {
            QMessageBox::warning(NULL, tr("警告"), tr("请输入服务器端口"));
            return;
        }

        tcpSock = new QTcpSocket(this);
        tcpSock->connectToHost(QHostAddress(ip), port.toUShort());
        connect(tcpSock, SIGNAL(connected()), this, SLOT(onTcpConnected()));
        connect(tcpSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onTcpError(QAbstractSocket::SocketError)));

        qDebug() << "TCP connecting..." << ip << port;
        break;

    case NET_PROTO_TCP_SERVER:
        ip = ui->comboBoxLocalAddr->currentText();
        port = ui->lineEditLocalPort->text();

        tcpServer = new QTcpServer(this);
        tcpServer->listen(QHostAddress(ip), port.toUShort());
        connect(tcpServer, SIGNAL(newConnection()), this, SLOT(onNewTcpConnect()));

        qDebug() << "TCP Listen on" << ip << port;
        break;

    case NET_PROTO_PING:
        rawSock = new QRawSocket(IPPROTO_ICMP);
        connect(rawSock, SIGNAL(readyRead()), SLOT(onDataReceived()));
        qDebug() << "Open ICMP socket";
        break;

    default:
        break;
    }

    initUi();
}

void MainWindow::onNewTcpConnect()
{
    QTcpSocket *cli = tcpServer->nextPendingConnection();

    tcpClients.insert(cli, cli->socketDescriptor());

    QString text = QString("%1:%2").arg(cli->peerAddress().toString()).arg(cli->peerPort());

    if (ui->comboBoxAddrList->count() < 1)
        ui->comboBoxAddrList->addItem("All");
    ui->comboBoxAddrList->insertItem(0, text, cli->socketDescriptor());
    ui->comboBoxAddrList->setCurrentIndex(0);

    connect(cli, SIGNAL(readyRead()), this, SLOT(onDataReceived()));
    connect(cli, SIGNAL(disconnected()), this, SLOT(onTcpDisconnected()));

    qDebug() << "New connection:" << text << cli->socketDescriptor();
}

void MainWindow::onTcpError(QAbstractSocket::SocketError err)
{
    int proto = ui->comboBoxProto->currentIndex();

    if (proto == NET_PROTO_TCP_CLIENT) {
        initUi();
        ui->statusBar->showMessage(tcpSock->errorString(), 2000);
        tcpSock->deleteLater();
    } else if (proto == NET_PROTO_TCP_SERVER) {
        QTcpSocket *cli = static_cast<QTcpSocket *>(sender());
        ui->statusBar->showMessage(cli->errorString(), 2000);
    }

    qDebug() << "TCP Socket error" << err;
}

void MainWindow::onTcpConnected()
{
    qDebug() << "tcp connected to server";

    ui->statusBar->showMessage("Connected", 2000);

    ui->pushButtonSend->setEnabled(true);

    connect(tcpSock, SIGNAL(readyRead()), this, SLOT(onDataReceived()));
    connect(tcpSock, SIGNAL(disconnected()), this, SLOT(onTcpDisconnected()));
}

void MainWindow::onTcpDisconnected()
{
    switch (ui->comboBoxProto->currentIndex()) {
    case NET_PROTO_TCP_CLIENT:
        qDebug() << "tcp connection closed by server";
        tcpSock->deleteLater();
        initUi();
        break;
    case NET_PROTO_TCP_SERVER: {
        QTcpSocket *cli = static_cast<QTcpSocket *>(sender());
        int sock = tcpClients.value(cli);
        int index = ui->comboBoxAddrList->findData(sock);

        tcpClients.remove(cli);
        ui->comboBoxAddrList->removeItem(index);

        qDebug() << "tcp connection closed:" << cli->peerAddress().toString() << cli->peerPort();

        cli->deleteLater();
        break;
    }
    default:
        break;
    }
}

void MainWindow::onDataReceived()
{
    QByteArray datagram;
    bool autoLinefeed = false;
    int proto = ui->comboBoxProto->currentIndex();

    while (1) {
        switch (proto) {
        case NET_PROTO_UDP:
            if (!udpSock->hasPendingDatagrams())
                return;
            datagram.resize(udpSock->pendingDatagramSize());
            rx += udpSock->readDatagram(datagram.data(), datagram.size());
            break;

        case NET_PROTO_TCP_CLIENT:
            if (!tcpSock->bytesAvailable())
                return;
            datagram.resize(tcpSock->bytesAvailable());
            rx += tcpSock->read(datagram.data(), datagram.size());
            break;

        case NET_PROTO_TCP_SERVER: {
            QTcpSocket *cli = static_cast<QTcpSocket *>(sender());
            if (!cli->bytesAvailable())
                return;
            datagram.resize(cli->bytesAvailable());
            rx += cli->read(datagram.data(), datagram.size());
            break;
        }
        case NET_PROTO_PING:
            if (!rawSock->bytesAvailable())
                return;
            datagram.resize(rawSock->bytesAvailable());
            rx += rawSock->read(datagram.data(), datagram.size());
            break;

        default:
            return;
        }

        if (ui->checkBoxStopShow->checkState()) {
            statusRx->setText(tr("接收") + QString("：%1").arg(rx));
            continue;
        }

        QString text;
        QFile file(toFile);
        QTextStream textStream;

        if (toFile.isEmpty()) {
            textStream.setString(&text);
        } else {
            if (!file.open(QIODevice::Text | QIODevice::Append))
                return;
            textStream.setDevice(&file);
        }

        if (proto == NET_PROTO_PING) {
            const char *data = datagram.constData();
            struct iphdr *iph = (struct iphdr *)data;
            quint8 ihl = iph->ihl << 2;
            struct icmphdr *icmph = (struct icmphdr *)(data + ihl);
            quint16 seq = ntohs(icmph->un.echo.sequence);
            quint64 tp = *((quint64 *)(data + ihl + sizeof(struct icmphdr)));
            quint32 rtt = QDateTime::currentMSecsSinceEpoch() - tp;
            QString from = QHostAddress(ntohl(iph->saddr)).toString();

            textStream << QString("%1 bytes from %2: seq=%3 ttl=%4 time")
                    .arg(datagram.size() - ihl).arg(from).arg(seq).arg(iph->ttl);

            if (rtt > 0)
                textStream << QString("= %1ms").arg(rtt) << endl;
            else
                textStream << "< 1ms" << endl;
        } else {
            if (ui->checkBoxShowTime->checkState()) {
                textStream << QDateTime::currentDateTime().toString("【yyyy-MM-dd hh:mm:ss:zzz】 ");
                autoLinefeed = true;
            } else if (ui->checkBoxAutoLinefeed->checkState()) {
                autoLinefeed = true;
            }

            if (ui->checkBoxShowHex->checkState())
                textStream << datagram.toHex(' ').toUpper();
            else
                textStream << datagram;

            if (autoLinefeed)
                textStream << endl;
            else if (ui->checkBoxShowHex->checkState())
                textStream << " ";
        }

        if (toFile.isEmpty())
            ui->plainTextEditRecv->insertPlainText(text);
        else
            file.close();

        statusRx->setText(tr("接收") + QString(": %1").arg(rx));
    }
}

void MainWindow::on_pushButtonSend_clicked()
{
    if (timer.isActive()) {
        timer.stop();
        ui->pushButtonSend->setText(tr("发送"));
        ui->checkBoxSendHex->setEnabled(true);
        ui->checkBoxAutoSend->setEnabled(true);
        ui->lineEditSendCycle->setEnabled(true);
        ui->plainTextEditSend->setEnabled(true);
        return;
    }

    if (ui->checkBoxAutoSend->checkState()) {
        if (ui->lineEditSendCycle->text().isEmpty())
            ui->lineEditSendCycle->setText("100");

        ui->checkBoxSendHex->setEnabled(false);
        ui->checkBoxAutoSend->setEnabled(false);
        ui->lineEditSendCycle->setEnabled(false);
        ui->plainTextEditSend->setEnabled(false);

        ui->pushButtonSend->setText(tr("停止发送"));

        timer.start(ui->lineEditSendCycle->text().toUInt());
        return;
    }

    doSend();
}

void MainWindow::on_checkBoxSendHex_stateChanged(int arg1)
{
    QByteArray text;

    text.append(ui->plainTextEditSend->toPlainText());
    ui->plainTextEditSend->clear();

    if (arg1) {
        ui->plainTextEditSend->insertPlainText(text.toHex(' ').toUpper());
    } else {
        ui->plainTextEditSend->insertPlainText(QByteArray::fromHex(text));
    }
}
void MainWindow::timeUpDate()
{
    doSend();
}

void MainWindow::doSend()
{
    QByteArray datagram;
    int proto = ui->comboBoxProto->currentIndex();

    if (proto != NET_PROTO_PING) {
        if (sendFile.isEmpty()) {
            datagram.append(ui->plainTextEditSend->toPlainText());
        } else {
            QFile file(sendFile);
            if (!file.open(QIODevice::ReadOnly))
                return;
            datagram = file.readAll();
            file.close();
        }

        if (ui->checkBoxSendHex->checkState())
            datagram = QByteArray::fromHex(datagram);
    }

    switch (proto) {
    case NET_PROTO_UDP: {
        if (ui->comboBoxAddrList->currentText() == "All") {
            for (int i = 0; i < ui->comboBoxAddrList->count() - 1; i++) {
                QString addr = ui->comboBoxAddrList->itemText(i).section(':', 0, 0);
                QString port = ui->comboBoxAddrList->itemText(i).section(':', 1, 1);
                tx += udpSock->writeDatagram(datagram, QHostAddress(addr), port.toUShort());
            }
        } else {
            QString addr = ui->comboBoxAddrList->currentText().section(':', 0, 0);
            QString port = ui->comboBoxAddrList->currentText().section(':', 1, 1);
            tx += udpSock->writeDatagram(datagram, QHostAddress(addr), port.toUShort());
        }
        break;
    }
    case NET_PROTO_TCP_CLIENT:
        tx += tcpSock->write(datagram);
        break;
    case NET_PROTO_TCP_SERVER: {
        if (ui->comboBoxAddrList->count() < 1)
            return;
        if (ui->comboBoxAddrList->currentText() == "All") {
            QMapIterator <QTcpSocket *, int> i(tcpClients);
            while(i.hasNext()) {
                i.next();
                QTcpSocket *cli = i.key();
                tx += cli->write(datagram);
            }
        } else {
            QTcpSocket *cli = tcpClients.key(ui->comboBoxAddrList->currentData().toInt());
            tx += cli->write(datagram);
        }
        break;
    }
    case NET_PROTO_PING: {
        if (ui->comboBoxAddrList->currentText() == "All") {
            for (int i = 0; i < ui->comboBoxAddrList->count() - 1; i++) {
                QString addr = ui->comboBoxAddrList->itemText(i);
                tx += rawSock->sendIcmpEcho(addr, 12, sequence++, 0);
            }
        } else {
            QString addr = ui->comboBoxAddrList->currentText();
            tx += rawSock->sendIcmpEcho(addr, 12, sequence++, 0);
        }
        break;
    }
    default:
        break;
    }

    statusTx->setText(tr("发送") + QString("：%1").arg(tx));
}

void MainWindow::on_plainTextEditRecv_textChanged()
{
    int max_bar = ui->plainTextEditRecv->verticalScrollBar()->maximum();
    ui->plainTextEditRecv->verticalScrollBar()->setValue(max_bar);
}

void MainWindow::on_plainTextEditRecv_customContextMenuRequested()
{
    recvMenu->exec(QCursor::pos());
}

void MainWindow::clearRecv()
{
    ui->plainTextEditRecv->clear();
}

void MainWindow::saveRecv()
{
    QString fileName = QFileDialog::getSaveFileName(this);
    if (fileName.isEmpty())
        return;

    QFile file(fileName);
    if (!file.open(QIODevice::Text | QIODevice::ReadWrite))
        return;

    QTextStream s(&file);
    s << ui->plainTextEditRecv->toPlainText();
    file.close();
}

void MainWindow::on_pushButtonAddrList_clicked()
{
    int proto = ui->comboBoxProto->currentIndex();

    switch (proto) {
    case NET_PROTO_TCP_SERVER: {
        if (ui->comboBoxAddrList->count() < 1)
            return;

        if (ui->comboBoxAddrList->currentText() == "All") {
            QMessageBox::warning(this, "", tr("请选择客户端"));
            return;
        }

        QTcpSocket *cli = tcpClients.key(ui->comboBoxAddrList->currentData().toInt());
        cli->deleteLater();
        ui->comboBoxAddrList->removeItem(ui->comboBoxAddrList->currentIndex());
        break;
    }
    case NET_PROTO_PING:
    case NET_PROTO_UDP:
        ui->comboBoxAddrList->clear();
        ui->comboBoxAddrList->addItem("All");
        break;
    default:
        break;
    }
}

void MainWindow::on_comboBoxProtoChanged()
{
    initUi();
}

void MainWindow::on_checkBoxShowTime_stateChanged(int checked)
{
    ui->checkBoxAutoLinefeed->setEnabled(!checked);
}

void MainWindow::on_checkBoxSendFile_stateChanged(int checked)
{
    if (checked) {
        sendFile = QFileDialog::getOpenFileName(this);
        if (sendFile.isEmpty()) {
            ui->checkBoxSendFile->setCheckState(Qt::Unchecked);
            return;
        }
        ui->plainTextEditSend->clear();
        ui->plainTextEditSend->appendPlainText(tr("外部文件数据源："));
        ui->plainTextEditSend->appendPlainText(sendFile);
        ui->plainTextEditSend->setEnabled(false);
    } else {
        sendFile = "";
        ui->plainTextEditSend->clear();
        ui->plainTextEditSend->appendPlainText("Test");
        ui->plainTextEditSend->setEnabled(true);
    }
}

void MainWindow::on_checkBoxToFile_stateChanged(int checked)
{
    if (checked) {
        toFile = QFileDialog::getSaveFileName(this);
        if (toFile.isEmpty()) {
            ui->checkBoxToFile->setCheckState(Qt::Unchecked);
            return;
        }
        ui->plainTextEditRecv->clear();
        ui->plainTextEditRecv->appendPlainText(tr("重定向至文件："));
        ui->plainTextEditRecv->appendPlainText(toFile);
        ui->plainTextEditRecv->setEnabled(false);
    } else {
        toFile = "";
        ui->plainTextEditRecv->clear();
        ui->plainTextEditRecv->setEnabled(true);
    }
}

void MainWindow::showAbout()
{
    QString text(tr("网络调试助手") + " v0.1.0\n\n");

    text += tr("项目主页：https://github.com/zhaojh329/net-assistant") + "\n\n";
    text += "Email: jianhuizhao329@gmail.com";

    QMessageBox::about(this, tr("关于"), text);
}

void MainWindow::showAboutQt()
{
    QMessageBox::aboutQt(this, tr("关于Qt"));
}

void MainWindow::setLanguage(QAction *action)
{
    static QTranslator *translator;
    QString lang = "Auto";

    if (action)
        lang = action->text();

    if (translator) {
        qApp->removeTranslator(translator);
        delete translator;
        translator = NULL;
    }

    if (lang == "Auto") {
        QLocale locale = QLocale::system();
        if (locale.language() == QLocale::Chinese)
            goto Translator;
        lang = "English";
    }

    if (lang == "English") {
        translator = new QTranslator(qApp);
        translator->load("i18n_en.qm");
        qApp->installTranslator(translator);
    }

Translator:
    ui->retranslateUi(this);
    initUi();
}
